﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://wpfimageviewer.codeplex.com
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using BrainTechLLC.ImageOperators;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BrainTechLLC;
using BrainTechLLC.FilterExtensions;
using System.Diagnostics;
using BrainTechLLC.ThreadSafeObjects;

namespace ImageAppDataModels
{
    public class FileImageCollection : ObservableCollection<IFileImage>
    {
        public CountInfo _latestCountInfo;
        protected FilterCollection _filters;

        // TODO - rethink... messy        
        public static int _latestLoadedFileCount;
        public static int _latestCachedImageSources;
        public static int _latestLoadedBitmapCount;
        public static long _LoadedBitmapBytes;
        public static long _LoadedThumbBytes;
        public static long _CachedImageSourceBytes;
        protected object _lock = new object();

        public FileImageCollection()
        {
        }

        public FilterCollection Filters
        {
            get { return _filters; }
            set
            {
                if (_filters != value)
                {
                    //DetachFilterEvents(_filters);
                    _filters = value;
                    //AttachFilterEvents(_filters);
                    SetFilters();
                    OnPropertyChanged(new PropertyChangedEventArgs("Filters"));
                }
            }
        }

        protected void SetFilters(FilterCollection filters)
        {
            List<IFileImage> list = null;
            lock (_lock)
            {
                list = this.ToList();
            }
            for (int n = 0; n < list.Count; n++)
            {
                var item = list[n];
                item.Filters = filters;
            }
        }

        protected void SetFilters()
        {
            SetFilters(_filters);
        }

        //public void AttachFilterEvents(FilterCollection filterCollection)
        //{
        //    if (filterCollection != null)
        //    {
        //    }
        //}

        //public void DetachFilterEvents(FilterCollection filterCollection)
        //{
        //    if (filterCollection != null)
        //    {
        //    }
        //}

        public void ClearAllItems()
        {
            lock (_lock)
            {
                Clear();
            }
        }

        public FileImage CreateNew(string s, FilterCollection filters)
        {
            FileImage fileImage = FileImageFactory.CreateNew(s, filters);
            this.AddFileImage(fileImage);
            return fileImage;
        }

        public void AddFileImage(IFileImage image)
        {
            lock (_lock)
            {
                image.Filters = _filters;
                Add(image);
            }
        }

        public List<IFileImage> GetAll()
        {
            var results = new List<IFileImage>();

            lock (_lock)
            {
                for (int n = 0; n < Count; n++)
                {
                    results.Add(this[n]);
                }
            }
            return results;
        }

        public CountInfo GetCounts()
        {
            CountInfo result = new CountInfo();

            lock (_lock)
            {
                for (int n = this.Count - 1; n >= 0; n--)
                {
                    var image = this[n];

                    if (image == null)
                    {
                        Console.WriteLine("Suck");
                    }
                    FileImage fi = image as FileImage;

                    try
                    {

                        if (image.ImageBytesCached != null)
                        {
                            result.LoadedFileCount += 1;
                        }

                        if (image.ImageBytesCached != null)
                        {
                            result.LoadedByteCount += image.ImageBytesCached.Length;
                        }

                        if (image.ImageSourceCached != null)
                        {
                            result.CachedImageSources += 1;
                            result.CachedImageSourceBytes += image.ImageSourceCached.EstimateImageSourceBytesUsed();
                        }

                        if (image.BitmapLoaded)
                        {
                            result.LoadedBitmapCount += 1;
                            result.LoadedBitmapBytes += fi.GetByteEstimateForBitmapCached();
                        }

                        if (image.ThumbnailCached != null)
                        {
                            result.LoadedThumbCount += 1;
                            result.LoadedThumbBytes += fi.GetByteEstimateForThumbnailCached();
                        }

                        if (image.ImageInfoCached != null)
                        {
                            result.LoadedAdditionalInfoCount += 1;
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }
            }

            Interlocked.Exchange(ref _latestLoadedFileCount, result.LoadedFileCount);
            Interlocked.Exchange(ref _latestCachedImageSources, result.CachedImageSources);
            Interlocked.Exchange(ref _latestLoadedBitmapCount, result.LoadedBitmapCount);
            Interlocked.Exchange(ref _latestCountInfo, result);

            Interlocked.Exchange(ref _LoadedBitmapBytes, result.LoadedBitmapBytes);
            Interlocked.Exchange(ref _LoadedThumbBytes, result.LoadedThumbBytes);
            Interlocked.Exchange(ref _CachedImageSourceBytes, result.CachedImageSourceBytes);
            return result;
        }

        public FileImageCollection(string pathName, FilterCollection filters, Action<string> pathDoesNotExist, ThreadSafeList<string> pathsDoNoExist)
        {
            Filters = filters;                        
            AddByPath(pathName, pathDoesNotExist, pathsDoNoExist);
        }

        public FileImageCollection(FilterCollection filters, Action<string> pathDoesNotExist, ThreadSafeList<string> pathsDoNotExist, params string[] pathNames)
        {
            Filters = filters;
            AddByPathNames(pathDoesNotExist, pathsDoNotExist, pathNames);
        }

        public List<IFileImage> AddByPath(string pathName, Action<string> pathDoesNotExist, ThreadSafeList<string> pathsDoNoExist)
        {
            ThreadSafeList<IFileImage> results = new ThreadSafeList<IFileImage>();
            if (!Directory.Exists(pathName))
            {
                if (pathDoesNotExist != null)
                {
                    pathDoesNotExist(pathName);
                }
                pathsDoNoExist.Add(pathName);
            }
            else
            {
                List<FileImage> images;
                try
                {
                    images = GetImagesFromPath(pathName);
                }
                catch
                {
                    if (pathDoesNotExist != null)
                    {
                        pathDoesNotExist(pathName);
                    }
                    pathsDoNoExist.Add(pathName);
                    return new List<IFileImage>();
                }
                var v = from image in images.AsParallel()
                        select image;

                v.ForAll(image =>
                {
                    AddFileImage(image);
                    results.Add(image);
                });
                //foreach (var image in images)
                //{
                //    AddFileImage(image);
                //    results.Add(image);
                //}
            }
            
            return results.AllItems;
        }

        public List<IFileImage> AddByPathNames(Action<string> pathDoesNotExist, ThreadSafeList<string> noLongerExist, params string[] pathNames)
        {
            //ThreadSafeList<IFileImage> results = new ThreadSafeList<IFileImage>();            
            List<IFileImage> results = new List<IFileImage>();            

            foreach (var pathName in pathNames)
            {
                results.AddRange(AddByPath(pathName, pathDoesNotExist, noLongerExist));
            }
            /*
            var paths = from pathName in pathNames.AsParallel() select AddByPath(pathName, pathDoesNotExist, noLongerExist);

            paths.ForAll(o => results.Add(o));
             */

            //foreach (var pathName in pathNames)
            //{
            //    results.AddRange(AddByPath(pathName));
            //}

            //return results.AllItems;
            return results;
        }

        public bool Delete(IFileImage fileImage)
        {
            if (this.RemoveFileImage(fileImage as FileImage))
            {
                fileImage.Delete();
                return true;
            }

            return false;
        }

        public IFileImage Find(string pathName)
        {
            return this.FirstOrDefault((fi) => fi.FileName.Equals(pathName, StringComparison.OrdinalIgnoreCase));
        }

        //public static List<string> GetFilesInPath(string path)
        //{
        //    List<string> results = new List<string>();
        //    var files = Directory.GetFiles(path, "*.jpg");

        //    foreach (var file in files)
        //    {
        //        results.Add(file);
        //    }

        //    files = Directory.GetFiles(path, "*.gif");

        //    foreach (var file in files)
        //    {
        //        results.Add(file);
        //    }

        //    return results;
        //}

        public List<FileImage> GetImagesFromPath(string path)
        {
            ThreadSafeList<FileImage> result = new ThreadSafeList<FileImage>();

            var files = Directory.GetFiles(path);
            // Thread.Sleep(10);

            var v = from file in files.AsParallel()
                    let ext = System.IO.Path.GetExtension(file)
                    where ext.IndexOf("jpg", StringComparison.OrdinalIgnoreCase) >= 0 || ext.IndexOf("gif", StringComparison.OrdinalIgnoreCase) >= 0
                    select file;

            v.ForAll(file =>
            {
                if (!string.IsNullOrEmpty(Settings.Values.FileNameFilter))
                {
                    if (file.IndexOf(Settings.Values.FileNameFilter, StringComparison.OrdinalIgnoreCase) < 0)
                        return;
                }

                FileImage fi = FileImageFactory.CreateNew(file, Filters);
                result.Add(fi);
            });
            
            return result.AllItems;
        }

        public bool RemoveFileImage(FileImage item)
        {
            if (item != null)
            {
                item.Release(ReleaseOptions.All);
                return Remove(item);
            }

            return false;
        }
    }


    public class CountInfo
    {
        public int LoadedFileCount;
        public int LoadedBitmapCount;
        public int LoadedThumbCount;
        public int LoadedAdditionalInfoCount;
        public long LoadedByteCount;
        public int CachedImageSources;

        public long LoadedBitmapBytes;
        public long LoadedThumbBytes;
        public long CachedImageSourceBytes;


    }
}
